package com.bomb.common.file;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * 使用Executors.newFixedThreadPool和callable 多线程实现,<br>
 * 获取文件目录下所有的文件总大小
 * @className ConcurrentTotalFileSize
 * @date 2015年8月31日 下午2:01:23
 * @author <a href="mailto:waferslove@sina.com">王星火</a>
 * @version V1.0
 */
public class ConcurrentTotalFileSize {

	/**
	 * 内部类--记录子文件夹和子文件的数量
	 * 
	 * @className SubDirectoriesAndSize
	 * @date 2015年8月31日 下午2:03:57
	 * @author <a href="mailto:waferslove@sina.com">王星火</a>
	 * @version V1.0
	 */
	class SubDirectoriesAndSize {
		public long size; // 子文件的数量
		public List<File> subDirectories; // 子文件夹

		public SubDirectoriesAndSize(long size, List<File> subDirectories) {
			this.size = size;
			this.subDirectories = subDirectories;
		}
	}

	/**
	 * 到一个包含该目录下所以子目录的列表,和该目录下所有文件大小的SubDirectoriesAndSize对象
	 * @param file
	 * @return
	 * @date 2015年8月31日 下午2:05:52
	 * @author <a href="mailto:waferslove@sina.com">王星火</a>
	 */
	private SubDirectoriesAndSize getTotalAndSubDirs(File file) {
		long total = 0;
		List<File> subDirectories = new ArrayList<File>();
		// 循环文件获取当前文件夹下的子文件夹
		if (file.isDirectory()) {
			File[] children = file.listFiles();
			if (children != null)
				for (File child : children) {
					if (child.isFile())
						total += child.length();
					else
						subDirectories.add(child);
				}
		}
		return new SubDirectoriesAndSize(total, subDirectories);
	}

	public long getTotalSizeOfFilesInDir(File file)
			throws InterruptedException, ExecutionException, TimeoutException {
		// 开启线程池
		ExecutorService service = Executors.newFixedThreadPool(100);
		try {
			long total = 0;
			List<File> directories = new ArrayList<File>();
			directories.add(file);
			while (!directories.isEmpty()) {
				// Callable的有返回值，这个返回值可以被Future拿到，也就是说，Future可以拿到异步执行任务的返回值
				List<Future<SubDirectoriesAndSize>> partialResults = new ArrayList<Future<SubDirectoriesAndSize>>();
				for (final File directory : directories) {
					// 将目录下的文件数量和文件夹类 放入到partialResults中
					partialResults.add(service
							.submit(new Callable<SubDirectoriesAndSize>() {
								public SubDirectoriesAndSize call() {
									return getTotalAndSubDirs(directory);
								}
							}));
				}
				// 将当前目录的文件夹清空
				directories.clear();
				for (Future<SubDirectoriesAndSize> partialResultFuture : partialResults) {
					SubDirectoriesAndSize subDirectoriesAndSize = partialResultFuture
							.get(100, TimeUnit.SECONDS);
					// 子文件夹存入到list中继续循环
					directories.addAll(subDirectoriesAndSize.subDirectories);
					total += subDirectoriesAndSize.size;
				}
			}
			return total;
		} finally {
			// 关闭线程池
			service.shutdown();
		}
	}

}
